﻿#region Using Statements
using System;
using System.Collections;
using System.Collections.Generic;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

using LuaInterface;
using LuaNetInterface;
#endregion

namespace _2DEngine
{
    /// <summary>
    /// A component for handling and displaying a Lua-based scripting console window/component.
    /// </summary>
    [LuaPackageAttribute(null, null)]
    public class ConsoleComponent : GameScreen, IEventListener
    {
        #region Structures

        internal struct ValidCharacter
        {
            public char Character;
            public char ShiftedCharacter;
            public ValidCharacter(char ch, char shiftCh)
            {
                Character = ch;
                ShiftedCharacter = shiftCh;
            }
        }

        private enum ConsoleState
        {
            Active,
            MovingOn,
            MovingOff,
            Hidden
        }

        #endregion

        #region Fields

        private LuaVirtualMachine lua;
        private IEventFilter eventFilter;

        private SpriteFont font;
        private Texture2D leftCorner;
        private Texture2D rightCorner;

        private bool active;
        private int width;
        private int height;
        private int logOffset;
        private string command = "";
        private const string prefix = "> ";
        private const string line = "---------------------\n";
        private const string message = "Type 'help()' to begin";
        private List<string> log = new List<string>();

        private int validDisplayHeight;
        private int currentOffset;
        private int targetOffset;

        private Hashtable _validChars;
        private ConsoleState state = ConsoleState.Hidden;

        #endregion

        #region Propeties

        public bool IsActive
        {
            get { return active; }
        }

        #endregion

        #region Initialization

        public ConsoleComponent(LuaVirtualMachine lua)
            : base("ConsoleScreen")
        {
            if (lua == null)
                lua = new LuaVirtualMachine();

            this.lua = lua;
            this.lua.RegisterLuaFunctions(this);
        }

        public override void Initialize()
        {
            log.Add(message);
            logOffset = 0;
            RegisterValidKeys();

            base.Initialize();
        }

        private void RegisterValidKeys()
        {
            _validChars = new Hashtable();

            // Register standard letters
            _validChars.Add(Keys.A, new ValidCharacter('a', 'A'));
            _validChars.Add(Keys.B, new ValidCharacter('b', 'B'));
            _validChars.Add(Keys.C, new ValidCharacter('c', 'C'));
            _validChars.Add(Keys.D, new ValidCharacter('d', 'D'));
            _validChars.Add(Keys.E, new ValidCharacter('e', 'E'));
            _validChars.Add(Keys.F, new ValidCharacter('f', 'F'));
            _validChars.Add(Keys.G, new ValidCharacter('g', 'G'));
            _validChars.Add(Keys.H, new ValidCharacter('h', 'H'));
            _validChars.Add(Keys.I, new ValidCharacter('i', 'I'));
            _validChars.Add(Keys.J, new ValidCharacter('j', 'J'));
            _validChars.Add(Keys.K, new ValidCharacter('k', 'K'));
            _validChars.Add(Keys.L, new ValidCharacter('l', 'L'));
            _validChars.Add(Keys.M, new ValidCharacter('m', 'M'));
            _validChars.Add(Keys.N, new ValidCharacter('n', 'N'));
            _validChars.Add(Keys.O, new ValidCharacter('o', 'O'));
            _validChars.Add(Keys.P, new ValidCharacter('p', 'P'));
            _validChars.Add(Keys.Q, new ValidCharacter('q', 'Q'));
            _validChars.Add(Keys.R, new ValidCharacter('r', 'R'));
            _validChars.Add(Keys.S, new ValidCharacter('s', 'S'));
            _validChars.Add(Keys.T, new ValidCharacter('t', 'T'));
            _validChars.Add(Keys.U, new ValidCharacter('u', 'U'));
            _validChars.Add(Keys.V, new ValidCharacter('v', 'V'));
            _validChars.Add(Keys.W, new ValidCharacter('w', 'W'));
            _validChars.Add(Keys.X, new ValidCharacter('x', 'X'));
            _validChars.Add(Keys.Y, new ValidCharacter('y', 'Y'));
            _validChars.Add(Keys.Z, new ValidCharacter('z', 'Z'));

            // Register numeric characters and corresponding symbols
            _validChars.Add(Keys.D1, new ValidCharacter('1', '!'));
            _validChars.Add(Keys.D2, new ValidCharacter('2', '"'));
            _validChars.Add(Keys.D3, new ValidCharacter('3', '#'));
            _validChars.Add(Keys.D4, new ValidCharacter('4', '$'));
            _validChars.Add(Keys.D5, new ValidCharacter('5', '%'));
            _validChars.Add(Keys.D6, new ValidCharacter('6', '^'));
            _validChars.Add(Keys.D7, new ValidCharacter('7', '&'));
            _validChars.Add(Keys.D8, new ValidCharacter('8', '*'));
            _validChars.Add(Keys.D9, new ValidCharacter('9', '('));
            _validChars.Add(Keys.D0, new ValidCharacter('0', ')'));

            // Register special characters
            _validChars.Add(Keys.Space, new ValidCharacter(' ', ' '));
            _validChars.Add(Keys.OemTilde, new ValidCharacter('`', '~'));
            _validChars.Add(Keys.OemMinus, new ValidCharacter('-', '_'));
            _validChars.Add(Keys.OemPlus, new ValidCharacter('=', '+'));
            _validChars.Add(Keys.OemOpenBrackets, new ValidCharacter('[', '{'));
            _validChars.Add(Keys.OemCloseBrackets, new ValidCharacter(']', '}'));
            _validChars.Add(Keys.OemBackslash, new ValidCharacter('\\', '|'));
            _validChars.Add(Keys.OemSemicolon, new ValidCharacter(';', ':'));
            _validChars.Add(Keys.OemQuotes, new ValidCharacter('\'', '@'));
            _validChars.Add(Keys.OemComma, new ValidCharacter(',', '<'));
            _validChars.Add(Keys.OemPeriod, new ValidCharacter('.', '>'));
            _validChars.Add(Keys.OemQuestion, new ValidCharacter('/', '?'));
        }

        public void LoadContent()
        {
            eventFilter = Engine.EventManager.RegisterEventListener(this);
            eventFilter.Subscribe("CONSOLE_OPEN");
            eventFilter.Subscribe("CONSOLE_CLOSE");
            eventFilter.Subscribe("CONSOLE_TOGGLE");

            font = Engine.Fonts["Console"];
            leftCorner = Engine.Content.Load<Texture2D>("Textures\\GUI\\LeftCorner");
            rightCorner = Engine.Content.Load<Texture2D>("Textures\\GUI\\RightCorner");

            Viewport viewport = Engine.GraphicsDevice.Viewport;
            width = viewport.Width;
            height = viewport.Height / 2 - 100;

            int prefixHeight = (int)font.MeasureString(prefix).Y;

            if (height < prefixHeight * 3)
                height = prefixHeight * 3;

            validDisplayHeight = height / prefixHeight - 2;

            if (validDisplayHeight < 1)
                validDisplayHeight = 1;

            currentOffset = targetOffset = height + 2;
        }

        public void UnloadContent()
        {
            eventFilter.UnsubscribeAll();
            Engine.EventManager.UnRegisterEventListener(this);
        }

        #endregion

        #region Update

        public void Update(GameTime gameTime)
        {
            UpdateTransition(gameTime);

            if (state == ConsoleState.Active)
            {
                KeyboardDevice keyboard = Engine.Services.GetService<KeyboardDevice>();
                MouseDevice mouse = Engine.Services.GetService<MouseDevice>();

                //
            }
        }

        private void UpdateTransition(GameTime gameTime)
        {
            //
        }

        #endregion

        #region Draw

        //

        #endregion

        #region Private Methods

        //

        #endregion

        #region Public Methods

        //

        #endregion

        #region Lua Functions

        //

        #endregion

        #region IEventListener Members

        public void OnEvent(string eventName, EventArgs args)
        {
            //
        }

        #endregion
    }
}